Hatena::ブログ(Diary)

Over&Out その後 このページをアンテナに追加 RSSフィード Twitter

2011-11-19

mecab での形態素解析を試してみました

https://github.com/FLCLjp/iPhone-libmecab

こちらに上げられている mecab を用いて形態素解析を行うサンプルアプリで、どういう結果がでるのか試してみました。


  • 入力文1:ゴルフに行ってきた

f:id:shu223:20111118120714p:image:left:w240



  • 入力文2:ゴルフ行ってきた

f:id:shu223:20111118120715p:image:left:w240



うーん、微妙だ。。


キーワード抽出的な使い方ができればと思ったのですが、助詞を抜いただけで「ゴルフ行」となるのでは精度的に厳しいものがあります。


どっかパラメータいじって調整の余地はあるのか、他にも使えそうな情報がとれるのか、調べてみました。


こちらの本家のページによると、mecabから形態素解析結果として得られる mecab_node_t 構造体の中身は、以下のようになっています。

struct mecab_node_t  *prev;  // 一つ前の形態素へのポインタ
struct mecab_node_t  *next;  // 一つ先の形態素へのポインタ

struct mecab_node_t  *enext; // 同じ位置で終わる形態素へのポインタ
struct mecab_node_t  *bnext; // 同じ開始位置で始まる形態素へのポインタ

char  *surface;             // 形態素の文字列情報
                            // NULL terminateされていません. 文字列として取り出すには
	      // strncpy(buf, node->feature, node->length) とする必要があります

char  *feature;             // CSV で表記された素性情報
unsigned int   length;      // 形態素の長さ
unsigned int   rlength;     // 形態素の長さ(先頭のスペースを含む)
unsigned int   id;          // 形態素に付与される ユニークID
unsigned short rcAttr;      // 右文脈 id
unsigned short lcAttr;      // 左文脈 id
unsigned short posid;       // 形態素 ID
unsigned char  char_type;   // 文字種情報
unsigned char  stat;        // 形態素の種類: 以下のマクロの値
                            // #define MECAB_NOR_NODE  0
                            // #define MECAB_UNK_NODE  1
                            // #define MECAB_BOS_NODE  2
                            // #define MECAB_EOS_NODE  3
unsigned char  isbest;      // ベスト解の場合 1, それ以外 0

float          alpha;       // forward backward の foward log 確率
float          beta;        // forward backward の backward log 確率
float          prob;        // 周辺確率
                            // alpha, beta, prob は -l 2 オプションを指定した時に定義されます

short          wcost;       // 単語生起コスト
long           cost;        // 累積コスト

この中でfeature、surface以外に使えそうな値は、char_type(文字種情報)、stat(形態素の種類)、isbest(ベスト解の場合 1, それ以外 0)、prob(周辺確率)あたりでしょうか。

char_typeやstatは品詞の手がかりになるかもしれませんし、isbestやprobは精度の低い結果をリジェクトするのに使えるかもしれません。


が、usr/include/mecab.h を見ると、

#if 1 /* MECAB_APPLE_ENHANCEMENT */
#else  /* original */
  unsigned char         isbest;
  unsigned int          sentence_length; /* it is avaialbe only when BOS node */
  float                 alpha;
  float                 beta;
  float                 prob;
#endif

こんな感じで、iPhoneにビルトインされたmecabではprobやisbestは使えなくされているようでした・・・



で、とりあえずchar_type(文字種情報)、stat(形態素の種類)を出力してみた結果


  • 入力文1:ゴルフに行ってきた

surface:ゴルフ, feature:補助, stat:1, char_type:0

surface:に, feature:煮, stat:0, char_type:5

surface:行, feature:補助, stat:1, char_type:0

surface:って, feature:って, stat:0, char_type:5

surface:きた, feature:北, stat:0, char_type:5


  • 入力文2:ゴルフ行ってきた

surface:ゴルフ行, feature:補助, stat:1, char_type:0

surface:って, feature:って, stat:0, char_type:5

surface:きた, feature:北, stat:0, char_type:5


ちょっとこの例文だけだと何とも言いがたいのと、mecabはiPhoneでちゃんと稼働している実績があるので何かやりようはあるはずなので、また追って研究します。



2011-11-18

Stats : Class to monitor the real-time memory usage in iOS app

What is "Stats"

"Stats" is a class to display set of parameters that indicate the load status such as memory usage, the number of UIView subclasses to create a directly below in real time.


When you run the included sample project will appear like this. (Stats is the black label in the upper left)


f:id:shu223:20110428232915p:image:w240


You will see that it is using about 16MB of memory, a total of five views. (run in the simulator)

Also, you can also see a slight rise in the CPU load when you hit the button to draw image.



Parameters and the units

From top to bottom,

  • The variation of memory usage [kB]
  • The total memory usage [kB]
  • The variation of CPU time [msec]
  • The number of UIView subclasses


How to use

A sample project is included.

https://github.com/shu223/Stats


  • Add Stats.h, Stats.m to your project
  • Import Stats.h
  • As with UILabel, add wherever you like.
self.stats = [[[Stats alloc] initWithFrame:CGRectMake(10.0, 30.0, 100.0, 60.0)] autorelease];
[self.view addSubview: stats];


2011-11-17

CIFilter の効果を一通り試せるサンプルコード(フィルタ名一覧つき)

iOS5から使えるようになった CIFilter の効果を一通り試せるサンプルプロジェクトをgithubに上げました。


こんな感じでフィルターを試せます。

(フィルタのパラメータはランダムに生成されるので、かける度に変わる場合もあります)


f:id:shu223:20111117111856p:image:left:w240

f:id:shu223:20111117111857p:image:left:w240



プロジェクト一式、こちらからダウンロードできます。

https://github.com/shu223/FilterDemo


注意点として、選んでも何も起こらないフィルターがたくさんあります

詳細は後述しますが、こちら、Apple の PocketCoreImage というサンプルコードを数行いじっただけのものなので、あんまり多種多様なフィルタに対応したつくりになってはいないのです。。

そういうフィルタはリストから除いてもよかったのですが、「どんなフィルタがあるのか?」を一覧できる意味もあるので、残してあります。


PocketCoreImageからの改変点

CIFilterは、下記のように、NSString型の名前を引数に渡してインスタンスを生成します。

CIFilter *newFilter = [CIFilter filterWithName:name];

で、ここに渡せる名前をずらずらっと列挙するために、awakeFromNibで次のようなコードで全ビルトインフィルタの名前を取得しています。

NSArray *filterNames;
filterNames = [CIFilter filterNamesInCategory:kCICategoryBuiltIn];
_availableFilters = [NSArray arrayWithArray:filterNames];


それと、PocketCoreImageでは、フィルタをかける箇所で、次のようにKVCを利用して元画像をフィルタに渡しています。

[filter setValue:_filteredImage forKey:@"inputImage"];

ここで、inputImageというアクセサを持たないフィルタもあるので、

if (![filter respondsToSelector:NSSelectorFromString(@"inputImage")]) {
    continue;
}

とチェックを入れて例外を回避しています。

(詳細はこちらの記事をご参照ください)



その他、コードの解説

もともと PocketCoreImage にあった部分なのですが、多種多様なパラメータを持つフィルタに対してランダム値を設定する部分はこうなっているよ、というのを紹介させていただきます。


  • CIFilterのattributesメソッドでパラメータ一覧を取得

(このあとここでは設定しないパラメータを取り除く処理が入りますが割愛)

NSDictionary *filterAttributes = [filter attributes];

  • NSNumber型のパラメータだけを取り出し、BOOL/Decimal/Integerそれぞれの型に応じたランダム値を設定
for (NSString *key in editableAttributes) {
    
    NSDictionary *attributeDictionary = [editableAttributes objectForKey:key];

    if ([[attributeDictionary objectForKey:kCIAttributeClass] isEqualToString:@"NSNumber"]) {
    
        // The number types are further broken down into sub types.  For our purposes, we
        // can group them into types that require either a boolean, float, or integer.
        if ([attributeDictionary objectForKey:kCIAttributeType] == kCIAttributeTypeBoolean)
        {
            NSInteger randomValue = (rand() % 2); 
            
            NSLog(@"Setting %i for key %@ of type BOOL", randomValue, key);
            [filter setValue:[NSNumber numberWithInteger:randomValue] forKey:key];
        }
        else if([attributeDictionary objectForKey:kCIAttributeType] == kCIAttributeTypeScalar ||
                [attributeDictionary objectForKey:kCIAttributeType] == kCIAttributeTypeDistance ||
                [attributeDictionary objectForKey:kCIAttributeType] == kCIAttributeTypeAngle)
        {
            // Get the min and max values
            float maximumValue = [[attributeDictionary valueForKey:kCIAttributeSliderMax] floatValue];
            float minimumValue = [[attributeDictionary valueForKey:kCIAttributeSliderMin] floatValue];
            
            float randomValue = randFloat(minimumValue, maximumValue);

            NSLog(@"Setting %f for key %@ of type Decimal", randomValue, key);
            [filter setValue:[NSNumber numberWithFloat:randomValue] forKey:key];
        }
        else
        {
            // Get the min and max values
            NSInteger maximumValue = [[attributeDictionary valueForKey:kCIAttributeMax] integerValue];
            NSInteger minimumValue = [[attributeDictionary valueForKey:kCIAttributeMin] integerValue];
            
            NSInteger randomValue = (rand() % (maximumValue - minimumValue)) + minimumValue;
            
            NSLog(@"Setting %i for key %@ of type Integer", randomValue, key);
            [filter setValue:[NSNumber numberWithInteger:randomValue] forKey:key];
        }
    
    }
    
}


おまけ:CIFilterのフィルタ名一覧

CIAdditionCompositing

CIAffineTransform

CICheckerboardGenerator

CIColorBlendMode

CIColorBurnBlendMode

CIColorControls

CIColorCube

CIColorDodgeBlendMode

CIColorInvert

CIColorMatrix

CIColorMonochrome

CIConstantColorGenerator

CICrop

CIDarkenBlendMode

CIDifferenceBlendMode

CIExclusionBlendMode

CIExposureAdjust

CIFalseColor

CIGammaAdjust

CIGaussianGradient

CIHardLightBlendMode

CIHighlightShadowAdjust

CIHueAdjust

CIHueBlendMode

CILightenBlendMode

CILinearGradient

CILuminosityBlendMode

CIMaximumCompositing

CIMinimumCompositing

CIMultiplyBlendMode

CIMultiplyCompositing

CIOverlayBlendMode

CIRadialGradient

CISaturationBlendMode

CIScreenBlendMode

CISepiaTone

CISoftLightBlendMode

CISourceAtopCompositing

CISourceInCompositing

CISourceOutCompositing

CISourceOverCompositing

CIStraightenFilter

CIStripesGenerator

CITemperatureAndTint

CIToneCurve

CIVibrance

CIVignette

CIWhitePointAdjust



2011-11-02

KVC で setValue:forUndefinedKey: エラーが発生する場合の対処法

たとえば、CIFilterを使っていて、下記のようにinputImageに値(画像)を渡そうとしていて、

[filter setValue:_filteredImage forKey:@"inputImage"];

この filter が inputImage というプロパティを持たないものだったとき(たとえば CICheckerboardGenerator)に、こんなエラーが出ます。

'NSUnknownKeyException', reason: '[<CICheckerboardGenerator 0x6828560> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key inputImage.'


解決法はこちらにとてもわかりやすく詳細な記事があって、以下は単なるその抜粋になります。


何が起きているのか?

  • setValue:ForKey: をあるオブジェクトへ投げたときに、当該keyが存在しない場合は setValue:forUndefinedKey: が投げられる。
  • この setValue:forUndefinedKey: はデフォルトでは例外(NSUndefinedKeyException)が発生する

解決方法

次のような解決方法が挙げられています。

  • 例外をキャッチして処理を続行 @try-@catch
  • valueForUndefinedKey: を実装(セッターの場合は setValue:forUndefinedKey:)
  • class_copyPropertyList( ) でプロパティリストを取得してチェック
  • respondsToSelector: でアクセッサ実装の有無をチェック

この中でも一番お手軽そうな、respondsToSelectorでチェック、を試してみました。


if (![filter respondsToSelector:NSSelectorFromString(@"inputImage")]) {
    return;
}
[filter setValue:_filteredImage forKey:@"inputImage"];

こんな感じで、inputImageというアクセサの有無をチェックすることで、とりあえず例外で止まることは回避できるようになりました。



2011-11-01

NSUserDefaults の内容を一括消去する方法

ゲームアプリ開発時等、動作確認用にリセット(初期化)ボタンをつけたくなる場合があり、NSUserDefaults の内容を一括消去する方法について調べてみました。


以下のコードでいけました。

NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];

以下でもほぼ同じ

NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] setPersistentDomain:[NSDictionary dictionary] forName:appDomain];

参考ページ



2009 | 08 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2013 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2014 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2015 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2016 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 11 | 12 |
2017 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2018 | 02 |