DSPはあなたにとって何を意味する? (和訳)

2012年1月5日

http://www.adexchanger.com/one-question/what-does-demand-side-platform-mean-to-you/

最近身近でちょっと話題だった記事を和訳しました。

What Does ‘Demand-Side Platform’ Mean To You?

What does DSP (demand-side platform) mean to you?

JG: Let me start by saying that one of the unfortunate things about ad technology is that we ruin words. I was in the middle of this before when I created the first ad exchange (AdECN) in 2004. We went out into the world and said, “We’ve created an ad exchange and we’re fair, neutral and transparent – and we run an auction for every impression.”

Then suddenly, that idea took hold. Before I knew it, there was no longer any distinctions (at least in powerpoint) between ad networks and ad exchanges.  And nearly every ad network transformed into either an exchange or a marketplace, or something other than an ad network. The word “exchange” started to become diluted. We then had to open every sales conversation with, “Let me tell you about our type of exchange.” We would oscillate between saying, “Our competitors are not exchanges,” to “They’re a different kind of exchange.”

So, in 2012 it is now 2006 all over again, except that instead of us squabbling about the term “ad exchange,” we’re diluting the term DSP, which has come to mean something other than a demand-side platform. Instead it’s come to mean,  “I plug into RTB (real-time bidding) inventory and I get access to the exchanges.”

There are often a variety of business models built on top of that – such as arbitrage focused business that are operating on 50 percent margins and offering little transparency – which I would argue is a business model that is closer to an ad network.

I’d argue that more often than not, most so-called DSPs are an outsourced agency, or they are a new type of ad network. Some DSPs have more service layers than they do technology—and their margins, their staffing, and sales pitch certainly do not lead with “platform.”

Anyway, it is admittedly self-serving to make this statement, but we’re one of the few companies that can actually say we’re a platform. We are a demand-side platform, or a buy-side platform. In fact, we often refer to ourselves as a buyer’s platform just because we’re trying to distinguish ourselves from the term DSP, which has come to mean so many different things.

As a buyer’s platform, we operate transparently. We leave a gap in the stack so that agencies and ad networks create the service layer – and can create and protect our client’s proprietary advantage when they play on our platform. We are trying to be the ad tech company that powers other ad tech companies instead of trying to compete with them all, which is different.  Most DSPs are competing with ad networks and ad agencies.  We don’t compete with them; we power them.

 

あなたにとってのDSPの意味とは?

 

私は広告技術に関する不幸なことの一つは、我々は言葉を台無しにすることであるということから始めてみましょう。私は2004年に最初のアドエクスチェンジ(AdECN)を作ろうとした時もそうだった。みんなは世界に向けてこう言った。

「私たちはアドエクスチェンジを始めます。それは公平で、中立で、透明です。そしてすべてのインプレッションに対してオークション方式です」。

そして突然、そのアイデアは保留しました。私がそれを知る前に、アドネットワークとアドエクスチェンジの間に区別は、(少なくともpowerpointの中では)ありませんでした。そして、ほとんどすべてのアドネットワークは、アドエクスチェンジかアドマーケットプレイス、またはそれ以外の何かに変わった。「アドエクスチェンジ」という単語は、薄まり始めました。そして私たちはセールスの度に、こんなこと言わなけれなりませんでした。

「私たちのアドエクスチェンジについてご紹介させてください。」

それで矛盾してくるだろう。

「私たちの競合はアドエクスチェンジではない」「彼らのアドエクスチェンジとは異なる」とか。

そう、2012年、それは2006年の再来です。「アドエクスチェンジ」について論争する代わりに、DSPという言葉の意味を曖昧にして、広告主サイドのプラットフォーム以外に以外の意味を持つようになってきました。私たちは用語DSPを曖昧にしています。それは需要側プラットフォーム以外にこのように意味されます。

「私はRTB (real-time bidding) でインベントリに接続します。そしてエクスチェンジにアクセスします。」

このように50%のマージンビジネスのようなモデルがよくある。私は、ほとんどのDSPは外注代理店、ある種のアドネットワークだと思う。そのDSPは、テクノロジー層よりも、サービス層を重要視していて、そのマージン率、人員配置、売り込み文句、、それは「プラットフォーム」としてリードすることはないでしょう。

我々は、「demand-side platform」または「buy-side platform」であるが、実際に、しばしば私たち自身を

「buyer’s platform」と呼びます。

理由としては、とても多くの異なったものを意味するようになってきた「DSP」という言葉から、自分たちを区別したいからです。

buyer’s platformとして、我々は透過的に動作します。代理店やアドネットワークは、サービス層を作成するような構造としている。我々のプラットフォームで動作させると、クライアントの独自の優位性を作成し、保護することができます 。私たちは、他社と競争しようとする代わりに、他のアドテクノロジー企業に動力を供給するようなアドテクノロジ企業であるとなろうとしています。そこが違います。ほとんどのDSPは広告ネットワークおよび広告代理店と競争していますが、私たちは競合しません。

私たちはそれらにパワーを与えます。

 

 

What’s your thought on Google’s position right now in the marketplace? Is it a fait accompli? Have they got it wrapped up?

No, and I know at times I’ve somewhat been in the minority on this. It’s not that we shouldn’t keep our eye on Google, but display and search are different. People often want to apply what’s happened in search to display. It just can’t happen that way. The primary reason it can’t happen that way is that in search, Google is the publisher 75% of the time.  In display, they rarely are the publisher. The argument that people often make is that Google has millions of advertisers plugged into them on the demand side, and they’ve got millions of publishers on the supply side and, as a result, the display ecosystem is theirs to lose. Unfortunately, most of the volume doesn’t come from the long tail and they have to continue to pay well.

The Admeld acquisition I think was a brilliant move for Google. But there is also risk. If Google takes too much margin –which is what’s required in order to really move the needle for investors accustomed to the high margins Google makes in search — than those publishers will eventually end up at other ad exchanges.

If Google decides to subsidize the business and accept lower margins, they may be able to sustain what they have. But I don’t see Google ever having more display market share than they have today.   Every major publisher is going to fight against Google growing in display.

That said, I’d like to see some of the other could-be-competitors actually compete with Google.

 

市場におけるグーグルの位置についてのあなたの考えは?もう勝ち組なの?

いいえ。

サーチ業界とディスプレイ業界は異なります。人々はよく、検索業界で起こったことを、ディスプレイにも適用しようとします。でもそれは起こりえません。主な理由は、サーチではGoogleのシェアが75%であるということに対し、ディスプレイにでは彼ら稀にしかない。

よく皆が議論するのは、グーグルは何百万もの広告主とパブリッシャーを接続したことで、ディスプレイ広告のエコシステムは失われるということ。でも、そのほとんどのボリュームはロングテール部分ではないため、彼らは、払い続けなければなりません。

私が思うadmeld買収は、Googleのための華麗な動きだった。 しかし、リスクもあります。Googleがあまりにも多くのマージン(サーチで慣れている高いマージン)を取る場合 、パブリッシャーは他のアドエクスチェンジでそれを終了させるでしょう。Googleは低マージンを受け入れる必要があると判断した場合、彼らが持っているもの維持できる可能性があります。しかし、私は、グーグルが、それらが今日持つより多くのディスプレイ市場占有率を常に持つとは思えません。すべての主要なパブリッシャーははディスプレイで成長するグーグルとの争うことになるでしょう。

 

(関連キーワード: ad teck / DSP/ ad exchange / RTB )

 

Learn about online behavioral advertising, privacy, cookies, and how this all works! (NAIのリンク集)

2012年1月4日

http://www.networkadvertising.org/managing/learn_more.asp

 

Learn about online behavioral advertising, privacy, cookies, and how this all works!

オンライン行動広告、プライバシー、クッキーそしてそれがどのように動くのか。

 

A way to support the websites and products you care about

ウェブサイト、またあなたの関心がある製品のために

 

Advertising supports most of the free content people enjoy viewing online.

Allowing cookies and online advertising to personalize services to your browser can be a great benefit to the websites you support, by helping them earn revenue.

It can also be a great benefit to you by helping ensure that you don’t see too much repetition or irrelevant advertising while you surf the web. To read more about the value of advertising, you can check out the following:

 

オンラインで楽しめるほとんどの無料コンテンツを支えるのは広告です。

クッキーを許可し、オンライン広告をパーソナライズ化を許することが、あなたが応援するウェブサイトが、収入を得るのを支援し大きな利益になるかもしれません。

さらに、それは、ウェブをサーフィンしている上で、あまりに繰り返されたり不適切だったりな広告を表示しないことを保証するので、あなたへの大きな利益でもあります。

広告の価値に関するさらなる情報はリンクをチェックしましょう。

 

 

On Cookies

クッキー

 

What are http cookies?How are they used? How can I control what cookies are set on my computer? This and much more, as you learn about cookies via the following links:

 

HTTPクッキーとは何か。どのように使用されるのか?自分のコンピュータのクッキーをどのように制御できるか?クッキーに関してはリンクをチェック。

 

On Regulation, Self-Regulation & Accountability

レギュレーション、自己規制&責任能力

 

Online privacy and behavioral advertising are hot topics! Read what regulators and business groups are thinking about these issues:

regulators

From business groups, technologists, and self-regulatory bodies:

オンライン・プライバシーおよび行動の広告は最新のトピックです!

どの規制者および企業集団がこれらの問題に関して考えているか読んでください。

 

(関連キーワード: NAI, FTC, HTTPクッキー, iAB)

What are the best similarity search engines? (Quora和訳)

2012年1月3日

http://www.quora.com/What-are-the-best-similarity-search-engines

 

What are the best similarity search engines?

最も優れた類似検索エンジンは?

How do you find people with similar interests on the web (not limited to FB, Quora, LinkedIn), How do you find similar cars, music, videos, clothes, images, products, books (not only on Amazon), electronic parts, web sites, related academic papers, stocks, homes for sale, service providers etc

あなたは、ウェブ上(FB、quora、LinkedInに限定されない)で似たような関心を持つ人々をどのように見つけるのですか 。
またあなたは、同じような、車、音楽、ビデオ、洋服、画像、製品、書籍(だけではなくアマゾンで)、電子部品、ウェブサイト、関連する学術論文、株、売り家、サービスプロバイダー、をどのように見つけるのか。

 

回答1

You can cluster queries in user query logs to suggest similar queries. I suggest to look at Microsoft researcher Ji-Rong Wen work.

ユーザーのクエリによるクラスタクエリは、類似クエリを推薦する。 私はMicrosoftの研究者の論文をお勧めします。

 

回答2

I assume you are talking about similarity search of images.

Tineye

It is a popular image matching site (frequented by quizzers like me anyway). It checks for proper copies of images and its database has grown significantly since its launch.

http://www.tineye.com/

 

私はあなたの画像の類似検索について話していると仮定します。
Tineye
それは一般的なイメージのマッチングサイトです。 それは画像の適切なコピーをチェックし、そのデータベースは、ローンチ以降大幅に成長してきました。
他のエンジンはあなたが入力したキーワードの少なくと少しは依存します。でも、これは私の知っている唯一の純粋な画像ベースの検索エンジンです。

What is a good way to create an item-item similarity matrix for a recommendation engine where items aren’t actually rated by users, but rather “used”, “clicked”, “bought” or “played” by users? (Quora和訳)

2012年1月2日

http://www.quora.com/What-is-a-good-way-to-create-an-item-item-similarity-matrix-for-a-recommendation-engine-where-items-arent-actually-rated-by-users-but-rather-used-clicked-bought-or-played-by-users

What is a good way to create an item-item similarity matrix for a recommendation engine where items aren’t actually rated by users, but rather “used”, “clicked”, “bought” or “played” by users?

ユーザーによる評価ではなく、ユーザーによって”クリック”、”使用”、”購入”、”プレイ”されたアイテムの場合で、
レコメンデーションエンジンのためのアイテムxアイテムの類似度行列を作成するための良い方法は何ですか?

 

 

This has to do with Collaborative Filtering. Looks like many algorithms assume users have given ratings for the items. I think there are countless scenarios where users do not “rate” an item on some scale, but their behavior provides a “rating” which is just as valuable. I’m looking to figure out how to calculate similarity between items in this scenario.

協調フィルタリング関連の話です。
多くのアルゴリズムは、ユーザーが項目の評価を与えていると仮定しています。
私はユーザの行動で実際に”評価”をしない無数のシナリオがあると考えます。
しかしユーザの行動は、実は価値のある”評価”をしています。
私はこのシナリオで項目間の類似度を計算する方法知りたいと思ってます。

 

 

回答1

 I’ve been using the Jaccard Coefficient, and specifically, the Tanimoto Coefficient, both described at http://en.wikipedia.org/wiki/Jaccard_index to calculate item-item similarity. They are both measures of overlap.

The formula is

AB / ( A + B – AB)

Where AB is the number of times both items were rated(bought) together, A is the number of times item A was bought, and B is the number of times item B was bought.

How I calculate this, in a map-reduce friendly way:
For each user, generate all of the (itemA, itemB) pairs for all of the items bought, and then keep track of the number of occurrences of each item-item pair.

The hard part is determining AB for each item-item pair. Once you have that figured out, calculating the Tanimoto coefficient is easy(refer to formula).

Consider this simplified example:
Customer A bought items 1, 2, and 3
Customer B bought items 2, 3, 4, and 6
Customer C bought items 1, 2 and 5

Items 1 and 2 would be considered most similar because they were bought together most often, compared to the number of times they were individually bought, and and thus their Jaccard score is .66. The AB would be 2 while A(item 1) = 2 and B(item2) = 3.

The similarity between items 3 and 6 would be 1 / (2 + 1 – 1), or .50 since they were bought together only once.

How you get the number of times (itemA/itemB) were bought together is up to you, my approach involved using python streaming so that I can run it on a hadoop cluster. I was inspired by Peter Skomoroch ‘s excellent article on similarity calculations using python streaming, found at

http://aws.amazon.com/articles/2294

I’m currently computing item-item similarity on about 10k items using over 3.5 million ‘purchase’ records, and it runs in only a few minutes. When you generate the (item,item) pairs for each item in a user’s history, you will generate a LOT of data but then you can reduce this when you sum the counts of occurrences.

A white-paper on this can be found at http://www.infosci.cornell.edu/weblab/papers/Bank2008.pdf

私はジャカール係数を使用しています、そしてまた谷本係数も関連します。それらのアイテム-アイテムの類似性を計算についてはwikipedia参照。

それらは両方ともオーバーラップの手段です。
その計算式は、
AB / ( A + B – AB)
ここでABは、AB同時に購入された回数、AはAがく購入された回数、BはBが購入された回数です。
私はこれを計算する方法として、MapReduceアルゴリズムに沿った方法として、

各ユーザーに対して、購入したアイテムのすべての「アイテム – アイテム」ペアを生成し、
その後、各「アイテム – アイテム」ペアの出現回数を追跡する。

難しい部分は、各アイテム-アイテムペアのABを決定することである
谷本係数を算出するのは簡単です。
以下のシンプルな例:
顧客Aは商品1,2,3を購入
顧客Bは商品2,3,4,6を購入
顧客Cは商品1,2,5を購入

 

アイテム1と2は、彼らが購入した回数に対して、最も頻繁に一緒に購入されているため、最も類似していると見なす、
ジャカールスコアは0.66である。AB=2、A=2、B=3。(これを上記の計算式に当てはめる)
アイテム3と6は、一度だけ一緒に購入されており、ジャカールスコアは0.50。
どのようにアイテムペアの同時購入回数を計算するか、pythonによるhadoop streamingのアプローチがあります。
私は現在350万人以上”購入”レコードを使用して約10,000のアイテム対し、アイテム-アイテム類似度を計算しています。
そしてそれはわずか数分で実行されます。
あなたがユーザの購入履歴らアイテム-アイテムペアを生成するときに大量のデータを生成しますが、出現回数のカウントすることとで、それを集計します。

参考論文があります。http://www.infosci.cornell.edu/weblab/papers/Bank2008.pdf

回答2

Perform cohort analysis on how much these different events lead to each other. Then you’ll be able to normalize the “downstream” likelihood (i.e., conditional probability) of events in relation to each other. For example, if 1 “clicked” event has .03 probability of leading to a “bought” event, now you can normalize to find the expected value of 1000 “clicked” events, in terms of “bought” outcomes.

これらの異なる出来事がどれくらい互いヘ導くかについての同世代分析を行なってください。
その後、互いに関しての出来事の「下流の」可能性(つまり条件付き確率)を標準化することができるでしょう。
例えば、今、1つの「クリックされた」出来事が「買われた」出来事に結びつく.03の可能性を持っている場合、1000の「クリックされた」出来事の期待値を見つけるために「買われた」結果の点から標準化することができます。

 

回答3

I think you might be interested in looking at this paper:
H. Yu, Y. Koren, C. Volinsky. Collaborative Filtering for Implicit Feedback Datasets. IEEE International Conference on Data Mining 2008.

http://research.yahoo.com/pub/2433

It includes a very thorough discussion of how to deal with implicit data (like clicks, views, etc); where, unlike ratings, you (a) don’t have negative feedback, and (b) the feedback you obtain can be used to measure the confidence you have that someone likes something, rather than their preference.
They also give some detailed descriptions of algorithms for this kind of data, ranging from neighborhood to latent factor models.

 

私は、この論文を見ることに、あなたは興味を持っているかもしれないと思います:
http://research.yahoo.com/pub/2433

それは、暗黙のデータ(クリック、視界などのような)に対処する方法の非常に完全な議論を含んでいます;
格付けと異なり、あなたが(a)ネガティブ・フィードバックを持たず、(b)得るフィードバックは、ユーザの好みではなく、誰かが何かを好きであることを測定するために使用することができます。
さらに、近隣から潜在している因子モデルまで、この種のデータ用アルゴリズムのいくつかの詳細な記述もあります。

 

回答4

It’s entirely reasonable to map these behaviors to some scalar values — maybe a page view is “0.1″, a video play is “0.3″ and a favorite is “1.0″. Then you can apply any technique that operates on rating values. Picking the right values is up to your domain and your intuition, though you could also use machine learning techniques to figure optimum weights even!

いくつかのスカラー値にこれらの行動を割り当てることは完全に合理的です
おそらく、ページビューは「0.1」です。ビデオ・プレーは「0.3」です。また、お気に入りは「1.0」です。
その後、値の評価上で作動するあらゆる技術を適用することができます。

さらに、あなたは最適の重量を計算するために機械学習技術を使用することができましたが、正しい値を取ることはあなたの領域とあなたの直観 さえあります!

 

回答5

One way would be to have separate matrices for each type of action.
You could interpolate the results from each to get your final output. Obviously “bought” would have a much higher weight than “clicked”… Instead of interpolation you could also use something like a backoff model.

1つの方法は各タイプのアクション用の個別のマトリックスを持つことでしょう。
最終産出物を得るために、各々の結果を設定します。
「買われた」は、明らかに「クリックされた」よりはるかに高い重量を持つだろう…
書き入れの代わりに、さらにbackoffモデルのようなものを使用することができました。

How does one determine similarity between people online? (Quora和訳)

2012年1月1日

http://www.quora.com/How-does-one-determine-similarity-between-people-online

 

How does one determine similarity between people online?

どのようにオンラインのユーザ間の類似度を決定するか?

How do you quantify similarities between people using shopping sites, social networks, Q&A sites etc (e.g how do Netflix, Amazon, Paypal, Twitter, Linkedin, Facebook, Quora calculate user similarity/assign users into groups)

どのようにショッピングサイト、ソーシャルネットワーク、QAサイトのユーザ間の類似度を定量化するか。

 

回答1

 

Here are some educated guesses about what serves as a basis for their work:

(1) Use vector models. For each user, look at the text he wrote.

Build a tf.idf vector. See http://en.wikipedia.org/wiki/TF_IDF for details.

Then compute the cosine between any two users.

You can supplement this with fancier Techniques such as LSI.

If you want to implement something such as similarity measure based on text, you can look at the

org.apache.lucene.search.similar package in Lucene (open source).

(2) Networking sites such as Facebook might simply look at how many friends you have in common and compute something like the Jaccard index .

 

 

彼らの仕事の基礎について、いくつかの経験から推測は以下のとおりです。

(1)ベクトルモデルを使用してください。 ユーザーごとに、彼が書いたテキストをもとに。TF-IDFベクトルを構築します。

その後、任意の2つのユーザー間のコサインを計算します。

またLSIの等の凝ったテクニックこれを補完することができます。

このようなテキストに基づいて類似度として何かを実装する場合は、(オープンソースの)Luceneライブラリがあります。

(2)Facebookなどのネットワーキングサイトは、単にあなたが共通に持ってどのように多くの友人を見て、Jaccardインデックスのようなものを計算しているのかもしれない。

(関連キーワード: LSI / Jaccard Index )

 

 

回答2

 

A good place to start is: Programming Collective Intelligence

http://www.amazon.com/Programming-Collective-Intelligence-Building-Applications/dp/0596529325

Whole books have been written on this area so answering it in a few words is not give anywhere near a full answer.

But if using the collaborative filtering approach, then find how many actions (e.g. products purchased, likes, friends) two people have in common. But to make it work well you have assign weights to the actions in common. The correlation value between two people is the sum of the weights of the actions. But the tricky part is assigning good weights to the actions. The weight has to be relative the two people, the cluster of the two people and the whole population.

 

 

集合知プログラミングは入門には良い。

その領域についてこの本に書かれている。

しかし、協調フィルタリング手法を使用している場合は、その後二人が共通して持ってどのように多くのアクション(購入などの商品、好き、友人)を見つける。

しかしそれはあなたが共通のアクションに重みを割り当てるているうまく機能させるために。

二人の間の相関値は、アクションの重みの合計です。

しかし、トリッキーな部分はアクションに適切な重みを割り当てています。 重量は相対的な二人、二人のクラスタと全体の人口にする必要があります。

 

回答3

Recommendation mining is very useful to determine similarity between peoples using shopping sites, social networks and Q&A sites on the basis of their likes, choices and on-line behavior

Some of popular recommendation engine are

 

You can also find similarity between in text posted by authors in Q&A, social networks, blogs etc. For that you can try out following techniques

  • Jaccard Index
  • Simrank
  • Vector space model with Cosine Similarity
  • Sorensen similarity index
  • BM25 Okapi model

 

 

レコメンドマイニングは、ショッピングサイト、ソーシャルネットワーク、Q&Aを用いて人々の間の類似性を決定するために非常に便利です。

有名なレコマンドエンジンとしては以下があります。

また、Q&A、ソーシャルネットワーク、ブログ等での、投稿者間の類似性を見つけることができます。

そのためには、次の方法を試してみることができます

  • ジャッカード係数
  • Simrank
  • コサイン類似度によるベクトル空間モデル
  • Sorensen similarity index
  • BM25 Okapi model

(関連キーワード: Jaccard Index / Simrank / Vector space model with Cosine Similarity / Sorensen similarity index / BM25 Okapi model )

 

 

 

 関連するQuoraのQA

 

 

 

 

 

 

 

 

 

 

 

TwitterのUser Streams APIを試してみた

2010年11月25日

こんばんは。最近、積極的にTwitterのストリーミングAPIを利用している(と思われる)サービスが増えてきましたね。何やらおもしろしそうなので少し触ってみる事に。

Streaming APIとは

The Twitter Streaming API allows high-throughput near-realtime access to various subsets of public and protected Twitter data.
http://dev.twitter.com/pages/streaming_api

  • Streaming API
  • User Streams
  • Site Streams (現在BETA)

ストリーミング系のAPIには3種類あって、それぞれ用途が分かれています。詳しくは上記リンク先を^^ 本当はSite Streamsを使いたいのだけど現在BETA版で申請が必要で、申請したけどなかなかレスがこないこともあり、今回はUser Streamsを試しました。

User Streamsとは

User Streams provides real-time updates of all data needed to update a desktop application display.
http://dev.twitter.com/pages/user_streams
User Streamsは、デスクトップアプリケーションの表示を更新するのに必要なすべてのデータをリアルタイムで提供してくれるAPIです。

すでにEchofonやTweetDeckではこのAPIに対応していて、とくにフォローが多い人はタイムラインが凄い勢いで流れていると思います。また、このAPIに対応することで、リプライの受信やメッセージの受信、ふぁぼられ、もちろんリツイートをリアルタイムに捕えることができます
以下、サンプルコードです。自分のツイートへのふぁぼりとリツイート、また自分への言及をリアルタイムに表示します。

お試し起動

以下のコマンドで。停止はCtrl+C。

1
# ruby user_timeline.rb
お試し実行結果

ソースコード(user_timeline.rb)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# -*- coding: utf-8 -*-
 
require 'rubygems'
require 'net/https'
require 'oauth'
require 'cgi'
require 'json'
 
CONSUMER_KEY = "XXXXXXXXXXXXX"
CONSUMER_SECRET = "XXXXXXXXXXXXX"
ACCESS_TOKEN        = "XXXXXXXXXXXXX"
ACCESS_TOKEN_SECRET = "XXXXXXXXXXXXX"
SCREEN_NAME = "yanaoki"
 
consumer = OAuth::Consumer.new( CONSUMER_KEY, CONSUMER_SECRET, :site => 'http://twitter.com') 
access_token = OAuth::AccessToken.new( consumer, ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
 
uri = URI.parse('https://userstream.twitter.com/2/user.json')
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
https.ca_file = '/path/to/ca.cert' # path to certificate
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
https.verify_depth = 5
https.start do |https|
  request = Net::HTTP::Get.new(uri.request_uri)
  request.oauth!(https, consumer, access_token)
  buf = ""
  https.request(request) do |response|
    response.read_body do |chunk|
      buf << chunk
      while (line = buf[/.+?(\r\n)+/m]) != nil
        begin
          buf.sub!(line,"")
          line.strip!
          status = JSON.parse(line)
          # mentions
          if status["entities"] and status["entities"]["user_mentions"]
            if status["entities"]["user_mentions"].select{|u| u['screen_name'] == SCREEN_NAME }.size > 0 
              puts status['text']
              puts "mention from #{status['user']['screen_name']}(#{status['user']['id']})"
            end
          end
          # retweets
          if status['retweeted_status'] and status['retweeted_status']['user']['screen_name'] == SCREEN_NAME
            puts "#{status['retweeted_status']['text']}"
            puts "retweeted by #{status['user']['screen_name']}(#{status['user']['id']})"
          end
          # favorites
          if status['event'] == 'favorite' and status['source']['screen_name'] != SCREEN_NAME
            puts "#{status['target_object']['text']}"
            puts "favorited by #{status['source']['screen_name']}(#{status['source']['id']})"
          end
        rescue
          # TODO
        end
      end
    end
  end
end

第7回データマイニング+WEB勉強会@東京で発表してきた

2010年9月27日

こんにちは。2010/09/26(日)、第7回データマイニング+WEB勉強会@東京に参加してきました。

この勉強会の特徴について

双方向の議論が多く、参加者の多くの方が発言するのが大きな特徴です。またIT系以外の方が参加される異業種交流ができる貴重な勉強回の一つです。内容については「理論〜詳細な実装〜実務」と幅広いものとなってます。
開始時の自己紹介、終了時の振り返り、で少なくとも全員2回ずつ発言する必要がありますw
今回も会場を提供してくださったニフティ・エンジニアサポート様に感謝!また、次回の勉強会は11/14(日)開催予定です。

今回は発表しました

以下発表資料です。

はじめてでもわかるベイズ分類器 -基礎からMahout実装まで-


機会学習も統計も素人ですが、素人なりに勉強した結果と、MahoutというHadoop(またはElastic MapReduce)上で動作する分類器の使い方を解説しています。ベイズ分類器の学習・評価データにはWikipediaのデータを利用してます。

参加者をまとめたホワイトボード

恒例の参加者一覧です。

プレゼン内で紹介した本とRubyのサンプルコード

「この本持っている人います?」の質問に7割近くの人が手を挙げたのが印象的でした。この「集合知プログラミング」の6章では、Pythonによるナイーブベイズ分類器の実装を解説していますが、それを私が使い慣れているRubyで実装してみました。

集合知プログラミング

まず使い方から

# 分類器生成
n = NaiveBayes.new
# 学習
n.train('Nobody owns the water.','good')
n.train('the quick rabbit jumps fences','good')
n.train('buy pharmaceuticals now','bad')
n.train('make quick money at the online casino','bad')
n.train('the quick brown fox jumps','good')
# 推定
puts n.classify("quick rabbit",default="unknown")
puts n.classify("quick money",default="unknown")
# 閾値を与える
n.setthreshold("bad",3.0)
# 推定
puts n.classify("quick money",default="unknown")

分類器のコード

# 特徴抽出クラス
class GetWordFeature
  def get_feature(doc)
    words = doc.split(' ')
    words.map{|w| w.downcase}.select{|w| w.length &lt; 20 &amp;&amp; w.length &gt; 2 }.uniq
  end
end
 
# 分類器の基底クラス
class Classifier
  def initialize(f)
    @fc,@cc,@feature = {},{},f
  end
 
  def incf(f,cat)
    @fc[f] ||= {}
    @fc[f][cat] ||= 0.0
    @fc[f][cat] = @fc[f][cat] + 1.0
  end
 
  def incc(cat)
    @cc[cat] ||= 0.0
    @cc[cat] = @cc[cat] + 1.0
  end
 
  def fcount(f,cat)
    @fc[f] ||= {}
    @fc[f][cat] ||= 0.0
    @fc[f][cat]
  end
 
  def catcount(cat)
    @cc[cat] ? @cc[cat].to_f : 0.0
  end
 
  def totalcount
    sum = 0
    @cc.each_value {|value| sum += value}
    return sum
  end
 
  def categories
    @cc.keys
  end
 
  # 条件付き確率 Pr(A|B)
  def fprob(f,cat)
    return 0 if catcount(cat) == 0 || fcount(f,cat) == nil
    fcount(f,cat) / catcount(cat)
  end
 
  # 重み付き確率
  def weightedprob(f, cat, weight=1.0, ap=0.5)
    # 通常の条件付き確率
    basicprob = fprob(f,cat)
    # この特徴がすべてのカテゴリ中に存在する確率
    totals = 0
    categories.each do |c|
      totals = totals + fcount(f,c) if fcount(f,c)
    end
    # 重み付けした平均計算
    ((weight*ap)+(totals*basicprob)) / (weight+totals)
  end
 
  def train(item, cat)
    features =  @feature.get_feature(item);
    features.each do |f|
      incf(f, cat)
    end
    incc(cat)
  end
end
 
# 単純ベイズ分類器
class NaiveBayes &lt; Classifier
  def initialize
    super(GetWordFeature.new)
    @thresholds = {}
  end
 
  # P(B|A):アイテム全体の与えられたカテゴリでの確率を求める(掛け合わせる)
  def docprob(item,cat)
    features = @feature.get_feature(item)
    p = 1.0
    features.each do |f|
      ep = weightedprob(f,cat)
      p = p * ep
    end
    return p
  end
 
  def prob(item,cat)
    catprob = catcount(cat) / totalcount
    docprob = docprob(item,cat)
    return docprob * catprob
  end
 
  def setthreshold(cat,t)
    @thresholds[cat] = t
  end
 
  def getthreshold(cat)
    @thresholds[cat] || 1.0
  end
 
  def classify(item, default=nil)
    probs,max,best = {},0.0,nil
    categories.each do |c|
      probs[c] = prob(item,c)
      if probs[c] &gt; max
        max = probs[c]
        best = c
      end
    end
    probs.each_key do |c|
      # (2番目に確率の高いもの * 閾値)と比較
      second = probs[c].to_f * getthreshold(best)
      return default if second &gt; probs[best]
    end
    return best
  end
end

以上です!

ブログにmixiチェックボタンを設置してみた

2010年9月10日

こんにちは。

mixiチェックボタン、本当に簡単に設置できました!
さきほど「mixi meetup 2010」にて発表があったmixiチェックボタンをさっそくブログのに貼り付けてみました。
個人ブログに簡単に導入するための便利プラグインがmixiエンジニアblogにて提供されていたのでそれを使いました。

このページに貼り付けてもあまり意味はないのだが、商品ページやニュース記事ページなど、集客を目的とするページでの設置であれば、それなりの効果があるのかもしれない。ただし、以下の意見もある。

これまでも日記に「いいね!」ボタンをつけることができたんだけど、「チェック」はニュースやmixiコレクションの中で興味のあるものに対して「チェック」できるという。まあ災害のニュースに「いいね!」ボタンはつけられないしね。「いいね!」より広い領域の事象に対する興味、関心を、友人、知人と共有するというコミュニケーションの形を提案しているわけだ。 「mixiチェック」正式発表【湯川】

Facebookの「いいね!」ボタンと「mixiチェック」ボタンの違いの一つとして、ネガティブなコンテンツやコメント付加に対応できるにあると湯川さんはおっしゃってるんですね。

ただし、楽天やYahooも、mixi対応するようなので、注目です。

RubyWorld Conference 2010に参加してきた

2010年9月7日

こんばんは。

昨日から二日間(2010年9月6日~2010年9月7日)、「RubyWorld Conference 2010」に参加してきました。

http://www.rubyworld-conf.org/

( Twitterハッシュタグ: #RWC2010 )

参加者の他県率は8割くらい(レセプション時の感覚)で、スーツ率はなんと9割くらいでした。参加者は、6日 415名、7日 693名とのことです。

発表内容からメモした言葉をちょっとだけ紹介し、後は写真をアップして寝ることにします。

基調講演:まつもとゆきひろ氏(@yukihiro_matz)『持続可能なRuby』

1993 ruby開発開始 ユーザまつもとさん1人

1995 ruby公開

2009 Rubyユーザ100万人(ガートナ調査結果)

2013 Rubyユーザ400万人(ガートナー予想)

すごいユーザ数の推移ですね。400万人予想はRails全盛期の予想らしく実際にはそこまでいかないらしいけど。

角谷信太郎氏(@kakutani)『ふつうのシステム開発~Rubyを活用した受託開発をアジャイルにするためのパターンの紹介』

「時を超えた建設の道: クリストファー アレグザンダー著」からの言葉

生きている花をつくろうとすれば、ピンセットで細胞を一つ一つ物理的に組み立てるのではなく種から育てるのであろう。

これは、ささりました。

何か事を成すときの考え方として、どんなケースでも当てはまる言葉ですよね。

そしてきっと誰でも思い当たる事があるでしょう。

Stevie Clifton氏(Animoto Productions)『How Ruby Enables Startup Success』

Stevie氏はANIMOTO(http://animoto.com/)という動画サービスのCTO。こういうサクセスストーリーを聞くのは楽しいです。とてつもない苦労をされてるんだろうけど、それにも増してサービスの提供を楽しんでいることが言葉の壁を超えて伝わってくる。クローゼット内のサーバで始めたサービス→EC2で30インスタンス規模まで拡大。Facebookアプリによって30台から3,000台までスケールアウト。そしてアーキテクチャの再構成。すべてのフェーズにてRubyとその周辺のプロダクトを採用したとのことです。

まさに海外でのRuby&Railsの成功例ですね。そしてANIMOTOのデモすげーかっこよかった。

-

全て1日目のレポートになってしまいましたが。2日目も楽天・三木谷社長の講演など内容は濃かったですよ。

-

以下写真。

会場:島根県立産業交流会館「くにびきメッセ」

-

ノベルティのエコ箸と、売店で売ってるRuby on 松江ラーメン(2食分)

ラーメンの箱の上部に書いてあるのはMatzのサインだろうか…。

-

Aホール:まつもとさん講演中

-

1日目昼食お弁当:ボリュームたっぷり

-

B会場

-

1日目:多目的ホール。夜のレセプションの開始直前

-

2日目昼食お弁当

-

なんか食べ物の写真ばかりで申し訳ない(汗)

以上です。何を言いたいかというと、来年も参加したいなーということです。

EC-CUBEの商品登録CSVデータを生成するRubyスクリプト

2010年8月31日

こんばんは。

EC-CUBE用のテストデータを登録するためのCSVファイルを作る必要があって、簡単なスクリプト書いたので公開しておきます。

今回は、楽天ランキングAPIのデータを使ってテストデータのCSVを作成し、EC-CUBEのテストデータとして登録する手順を紹介します。
間違ってもそのまま公開しないように!

EC-CUBEのWeb管理ツールで手動でカテゴリ登録する

まず、EC-CUBEのWeb管理ツールでカテゴリを一つたとえば「ゴルフ」を手動で登録します。
登録したカテゴリのIDを管理ツール上で確認します。
ここでは「ゴルフ」のカテゴリIDが「5」だったとします。

楽天ジャンルIDの取得する

楽天のジャンル一覧で「ゴルフ」のジャンルIDを確認します。
ゴルフのジャンルIDは「101077」でした。
楽天ジャンルID(genreId)検索

必要なコードを準備

Simple JSON parser & builder
以下のサイトからJSON解析スクリプトをダウンロードし「jsonparser.rb」とします。ここにも置いておきます。
http://rubyforge.org/snippet/detail.php?type=snippet&id=148
httpclient
画像ファイルを取得するのにhttpclientを利用しているのでインストールします。

$ sudo gem install httpclient

以下のrubyスクリプトをコピーして適当な名前で保存します。
ここでは「itemgen.rb」とします。
ざっくしとした説明です。

  • setupメソッドでIDで設定を行う
  • csv_formatメソッドでCSV形式を定義する
  • rewriteメソッドでCSVの内容を定義する
$KCODE='u'
require 'rubygems'
require 'httpclient'
require 'open-uri'
require 'kconv'
require 'jsonparser.rb'
require "fileutils"
require 'jcode'
 
# 初期設定
def setup
  $developer_id = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'  # APIのためのデベロッパID
  $img_dir = 'img'                         # 画像保存ディレクトリ名
  $item_csv_filename = "item.csv"   # 商品CSVファイル名
  $genre_id = ARGV[0]                  # 楽天ジャンルID
  $category_id = ARGV[1]             # カテゴリID
  $max_page = ARGV[2]               # 取得ページ数(1ページ30商品で10ページまであるらしい)
end
 
# CVSフォーマット(HashをsortしてArray返してるので注意)
def csv_format
  {
    0 =&gt;  "商品ID",
    1 =&gt; "商品規格ID",
    2 =&gt; "規格名1",
    3 =&gt; "規格名2",
    4 =&gt; "商品名(必須)",
    5 =&gt; "公開フラグ(1:公開 2:非公開)(必須)",
    6 =&gt; "商品ステータス(必須)",
    7 =&gt; "商品コード",
    8 =&gt; "通常価格 ",
    9 =&gt; "販売価格(必須)",
    10 =&gt;"在庫数",
    11 =&gt;"送料",
    12 =&gt;"ポイント付与率(必須)",
    13 =&gt;"購入制限",
    14 =&gt;"メーカーURL",
    15 =&gt;"検索ワード",
    16 =&gt;"備考欄(SHOP専用)",
    17 =&gt;"一覧-メインコメント(必須)",
    18 =&gt;"一覧-メイン画像(必須)",
    19 =&gt;"メインコメント(必須)",
    20 =&gt;"メイン画像(必須)",
    21 =&gt;"メイン拡大画像",
    22 =&gt;"カラー比較画像",
    23 =&gt;"商品詳細ファイル",
    24 =&gt;"詳細-サブタイトル(1)",
    25 =&gt;"詳細-サブコメント(1)",
    26 =&gt;"詳細-サブ画像(1)",
    27 =&gt;"詳細-サブ拡大画像(1)",
    28 =&gt;"詳細-サブタイトル(2)",
    29 =&gt;"詳細-サブコメント(2)",
    30 =&gt;"詳細-サブ画像(2)",
    31 =&gt;"詳細-サブ拡大画像(2)",
    32 =&gt;"詳細-サブタイトル(3)",
    33 =&gt;"詳細-サブコメント(3)",
    34 =&gt;"詳細-サブ画像(3)",
    35 =&gt;"詳細-サブ拡大画像(3)",
    36 =&gt;"詳細-サブタイトル(4)",
    37 =&gt;"詳細-サブコメント(4)",
    38 =&gt;"詳細-サブ画像(4)",
    39 =&gt;"詳細-サブ拡大画像(4)",
    40 =&gt;"詳細-サブタイトル(5)",
    41 =&gt;"詳細-サブコメント(5)",
    42 =&gt;"詳細-サブ画像(5)",
    43 =&gt;"詳細-サブ拡大画像(5)",
    44 =&gt;"発送日目安",
    45 =&gt;"おすすめ商品(1)",
    46 =&gt;"詳細-サブコメント(1)",
    47 =&gt;"おすすめ商品(2)",
    48 =&gt;"詳細-サブコメント(2)",
    49 =&gt;"おすすめ商品(3)",
    50 =&gt;"詳細-サブコメント(3)",
    51 =&gt;"おすすめ商品(4)",
    52 =&gt;"詳細-サブコメント(4)",
    53 =&gt;"おすすめ商品(5)",
    54 =&gt;"詳細-サブコメント(5)",
    55 =&gt;"おすすめ商品(6)",
    56 =&gt;"詳細-サブコメント(6)",
    57 =&gt;"商品カテゴリ(必須)"
  }.sort_by{|k,v|k}
end
 
# CSVの値を定義(フォーマットの列番号に対応。xにはAPIで取得したitemが入る)
def rewrite
  {
    4  =&gt;lambda{|x| cut_off(x["itemName"].to_s.toutf8.gsub(/【.[^【]*/, '').gsub("楽天",''),45)}, #【】は取る
    5  =&gt;lambda{|x| "1"},
    6  =&gt;lambda{|x| "0"},
    7  =&gt;lambda{|x| x["itemCode"]},
    9  =&gt;lambda{|x| x["itemPrice"]},
    10 =&gt;lambda{|x| "20"},
    12 =&gt;lambda{|x| x["pointRate"]},
    17 =&gt;lambda{|x| s = cut_off(x["itemCaption"].to_s.toutf8.gsub("楽天",'').gsub('。','。'),50) ; s == "" ? "-" : s},
    18 =&gt;lambda{|x| image_get(x["smallImageUrl"],x["itemCode"] + "_s.gif")},
    19 =&gt;lambda{|x| s = x["itemCaption"].to_s.toutf8.gsub("楽天",'').gsub('。','。') ; s == "" ? "-" : s},
    20 =&gt;lambda{|x| image_get(x["mediumImageUrl"],x["itemCode"] + "_m.gif")},
    57 =&gt;lambda{|x| $category_id}
  }
end
 
def image_get(image_url,save_file_name)
  hc = HTTPClient.new
  f = File.open("#{$img_dir}/" + save_file_name, "wb")
  f.print(hc.get_content(image_url))
  f.close
  save_file_name
end
 
def api_call(uri)
  json_string = ''
  open(uri){|f| json_string = f.read }
  parser = JsonParser.new
  parser.parse(json_string)
end
 
def cut_off(text,len)
  if text != nil
    text.jlength &lt; len ? text : text.scan(/^.{#{len}}/m)[0] + "…"
  else
    ''
  end
end
 
setup
# ファイルを掃除しとく
FileUtils.remove_entry($img_dir,true)
FileUtils.mkdir($img_dir)
FileUtils.rm($item_csv_filename, {:force=&gt;true})
File.open($item_csv_filename,'w') do |f|
  # ヘッダ行を追加
  f.puts(csv_format.collect{|col| "\"#{col[1]}\""}.join(','))
  (1..$max_page.to_i).each do |page|
    items = []
    ranking_api_url = "http://api.rakuten.co.jp/rws/3.0/json?developerId=#{$developer_id}&amp;operation=ItemRanking&amp;version=2010-08-05&amp;genreId=#{$genre_id}&amp;page=#{page}"
    # APIを呼び出して戻り値のアイテムをもとにCSV行を作成
    obj = api_call(ranking_api_url)
    exit unless obj["Body"]["ItemRanking"]
    rakuten_items = obj["Body"]["ItemRanking"]["Items"]["Item"]
    puts "ページ#{page} から #{rakuten_items.size} 件取得しました。"
    rakuten_items.each do |item|
      items &lt;&lt; csv_format.collect do |col|
        i=col[0]
        rewrite[i] ? rewrite[i].call(item) : ""
      end
    end
    # 出力
    items.each do |item|
      f.puts(item.collect{|col| "\"#{col.to_s.gsub(',','')}\""}.join(','))
    end
  end
end
実行する

以下のコマンドで実行します。
パラメータは「ジャンルID カテゴリID 取得ページ数」です。

$ ruby itemgen.rb 101077 5 3
  • item.csv
  • imgディレクトリ

が生成されます。

画像を配置する

先に画像を配置しておく必要があるので、imgディレクトリ内の全画像を、
「html/upload/save_image/」に配置します。

登録する

Web管理ツールからCSVファイルを登録します。

完了

以上です。いろいろと使えそうな気がしますね。